package order

import (
	"context"
	"strconv"

	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/utils/pointy"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/internal/utils/errorhandler"
	"mall/service/order/rpc/types/order"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetOrderByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetOrderByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetOrderByIdLogic {
	return &BackendGetOrderByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetOrderByIdLogic) BackendGetOrderById(in *order.OrderIdReq) (*order.OrderInfo, error) {
	if in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	trade, err := l.svcCtx.Order.FindOne(l.ctx, in.Id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	oid := trade.ID
	resp := &order.OrderInfo{
		Id:              &trade.ID,
		ParentId:        &trade.ParentID,
		UserId:          &trade.UserID,
		UserRank:        &trade.UserRank,
		Buyer:           &trade.Buyer,
		Sn:              &trade.OrderSN,
		OrderType:       pointy.GetPointer(uint32(trade.OrderType)),
		SourceType:      pointy.GetPointer(uint32(trade.SourceType)),
		Number:          pointy.GetPointer(uint32(trade.Quantity)),
		GemAmount:       pointy.GetPointer(moneyx.FormatGem(int64(trade.GemAmount))),
		RetailAmount:    pointy.GetPointer(moneyx.FormatAmount(int64(trade.RetailAmount))),
		Freight:         pointy.GetPointer(moneyx.FormatAmount(int64(trade.Freight))),
		DiscountAmount:  pointy.GetPointer(moneyx.FormatAmount(int64(trade.DiscountAmount))),
		AdjustAmount:    pointy.GetPointer(moneyx.FormatAmount(int64(trade.AdjustAmount))),
		ActualAmount:    pointy.GetPointer(moneyx.FormatAmount(int64(trade.ActualAmount))),
		DepositAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(trade.DepositAmount))),
		BalanceAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(trade.BalanceAmount))),
		RemainingAmount: pointy.GetPointer(moneyx.FormatAmount(int64(trade.RemainingAmount))),
		RefundAmount:    pointy.GetPointer(moneyx.FormatAmount(int64(trade.RefundAmount))),
		Gems:            &trade.Gems,
		TradeState:      pointy.GetPointer(uint32(trade.TradeState)),
		Remark:          &trade.Remark,
		SellerMemo:      &trade.SellerMemo,
		CreatedAt:       pointy.GetPointer(modelx.FormatTime(trade.CreatedAt, "")),
		UpdatedAt:       pointy.GetPointer(modelx.FormatTime(trade.UpdatedAt, "")),
		DeletedAt:       pointy.GetPointer(modelx.FormatNullDotTime(trade.DeletedAt, "")),
		PaidAt:          pointy.GetPointer(modelx.FormatNullDotTime(trade.PaidAt, "")),
		ShippedAt:       pointy.GetPointer(modelx.FormatNullDotTime(trade.ShippedAt, "")),
		DeliveredAt:     pointy.GetPointer(modelx.FormatNullDotTime(trade.DeliveredAt, "")),
		ConfirmedAt:     pointy.GetPointer(modelx.FormatNullDotTime(trade.ConfirmedAt, "")),
		ReviewedAt:      pointy.GetPointer(modelx.FormatNullDotTime(trade.ReviewedAt, "")),
		FulfilledAt:     pointy.GetPointer(modelx.FormatNullDotTime(trade.FulfilledAt, "")),
		ClosedAt:        pointy.GetPointer(modelx.FormatNullDotTime(trade.ClosedAt, "")),
		AutoComfirmDays: pointy.GetPointer(uint32(trade.AutoComfirmDays)),
		Growth:          pointy.GetPointer(uint32(trade.Growth)),
		Integrals:       pointy.GetPointer(uint32(trade.Integrals)),
	}

	if in.WithSkus != nil && *in.WithSkus > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderItemColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetItemList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Skus = append(resp.Skus, &order.OrderSkuInfo{
					Id:             &v.OrderItemID,
					OrderId:        &v.OrderID,
					ProductCode:    &v.ProductCode,
					SkuId:          &v.SkuID,
					SkuCode:        &v.SkuCode,
					Sku:            &v.Sku,
					ImageId:        pointy.GetPointer(strconv.FormatUint(v.SkuImageID, 10)),
					ImageUrl:       &v.SkuImageURL,
					ProductId:      &v.ProductID,
					EntryId:        &v.EntryID,
					Title:          &v.Title,
					Slug:           &v.Slug,
					ProductType:    pointy.GetPointer(uint32(v.ProductType)),
					BrandId:        &v.BrandID,
					BrandTitle:     &v.BrandTitle,
					BrandSlug:      &v.BrandSlug,
					GemPrice:       pointy.GetPointer(moneyx.FormatGem(int64(v.GemPrice))),
					RetailPrice:    pointy.GetPointer(moneyx.FormatAmount(int64(v.RetailPrice))),
					Quantity:       pointy.GetPointer(uint32(v.Quantity)),
					Weight:         pointy.GetPointer(moneyx.FormatWeight(int64(v.Weight))),
					TradeState:     pointy.GetPointer(uint32(v.TradeState)),
					Status:         pointy.GetPointer(uint32(v.Status)),
					GemAmount:      pointy.GetPointer(moneyx.FormatGem(int64(v.GemAmount))),
					RetailAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.RetailAmount))),
					Freight:        pointy.GetPointer(moneyx.FormatAmount(int64(v.Freight))),
					DiscountAmount: pointy.GetPointer(moneyx.FormatAmount(int64(v.DiscountAmount))),
					AdjustAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.AdjustAmount))),
					ActualAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.ActualAmount))),
					RefundAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.RefundAmount))),
					RefundQuantity: pointy.GetPointer(uint32(v.RefundQuantity)),
					PostId:         &v.PostID,
					InviterId:      &v.InviterID,
				})
			}
		}
	}

	if in.WithAddresses != nil && *in.WithAddresses > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderAddressColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetAddressList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Addresses = append(resp.Addresses, &order.OrderAddressInfo{
					Id:         &v.OrderAddressID,
					OrderId:    &v.OrderID,
					UserId:     &v.UserID,
					Consignee:  &v.Consignee,
					Mobile:     &v.Mobile,
					Province:   &v.Province,
					City:       &v.City,
					District:   &v.District,
					Street:     &v.Street,
					Address:    &v.DetailedAddress,
					PostalCode: &v.PostalCode,
					RegionCode: &v.RegionCode,
					Label:      &v.Label,
					Status:     pointy.GetPointer(uint32(v.Status)),
				})
			}
		}
	}

	if in.WithAdjustments != nil && *in.WithAdjustments > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderAdjustmentColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetAdjustmentList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Adjustments = append(resp.Adjustments, &order.OrderAdjustmentInfo{
					Id:         &v.OrderAdjustmentID,
					OrderId:    &v.OrderID,
					Amount:     pointy.GetPointer(moneyx.FormatAmount(int64(v.Amount))),
					Memo:       &v.Memo,
					Status:     pointy.GetPointer(uint32(v.Status)),
					OperatedBy: &v.OperatedBy,
					OperatedAt: pointy.GetPointer(modelx.FormatNullDotTime(v.OperatedAt, "")),
				})
			}
		}
	}

	if in.WithDiscounts != nil && *in.WithDiscounts > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderDiscountColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetDiscountList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Discounts = append(resp.Discounts, &order.OrderDiscountInfo{
					Id:               &v.OrderDiscountID,
					OrderId:          &v.OrderID,
					SkuId:            &v.SkuID,
					ProductId:        &v.ProductID,
					Title:            &v.Title,
					Slug:             &v.Slug,
					ActivityId:       &v.ActivityID,
					ActivityRuleId:   &v.ActivityRuleID,
					CouponTemplateId: &v.CouponTemplateID,
					CouponId:         &v.CouponID,
					GrouponAmount:    pointy.GetPointer(moneyx.FormatAmount(int64(v.GrouponAmount))),
					WholesaleAmount:  pointy.GetPointer(moneyx.FormatAmount(int64(v.WholesaleAmount))),
					CouponAmount:     pointy.GetPointer(moneyx.FormatAmount(int64(v.CouponAmount))),
					ActivityAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.ActivityAmount))),
					IntegralAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.IntegralAmount))),
					DiscountAmount:   pointy.GetPointer(moneyx.FormatAmount(int64(v.DiscountAmount))),
					Integrals:        &v.Integrals,
				})
			}
		}
	}

	if in.WithPayments != nil && *in.WithPayments > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderPaymentColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetPaymentList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Payments = append(resp.Payments, &order.OrderPaymentInfo{
					Id:      &v.OrderPaymentID,
					OrderId: &v.OrderID,
					No:      &v.No,
					Amount:  pointy.GetPointer(moneyx.FormatAmount(int64(v.Amount))),
					Type:    pointy.GetPointer(uint32(v.Type)),
					Name:    &v.Name,
					Code:    &v.Code,
					Status:  pointy.GetPointer(uint32(v.Status)),
					PaidAt:  pointy.GetPointer(modelx.FormatNullDotTime(v.PaidAt, "")),
				})
			}
		}
	}

	if in.WithShipments != nil && *in.WithShipments > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderShipmentColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetShipmentList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Shipments = append(resp.Shipments, &order.OrderShipmentInfo{
					Id:        &v.OrderShipmentID,
					OrderId:   &v.OrderID,
					No:        &v.No,
					Type:      pointy.GetPointer(uint32(v.Type)),
					Name:      &v.Name,
					Code:      &v.Code,
					Status:    pointy.GetPointer(uint32(v.Status)),
					UpdatedAt: pointy.GetPointer(modelx.FormatTime(v.UpdatedAt, "")),
				})
			}
		}
	}

	if in.WithLogs != nil && *in.WithLogs > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.OrderOperateLogColumns.OrderID] = map[string][]any{
			"equalTo": {oid},
		}
		list, _, err := l.svcCtx.Order.GetLogList(l.ctx, model.M{}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				resp.Logs = append(resp.Logs, &order.OrderOperateLogInfo{
					Id:         &v.LogID,
					OrderId:    &v.OrderID,
					TradeState: pointy.GetPointer(uint32(v.TradeState)),
					NewState:   pointy.GetPointer(uint32(v.NewState)),
					Type:       pointy.GetPointer(uint32(v.Type)),
					Name:       &v.Name,
					Code:       &v.Code,
					Status:     pointy.GetPointer(uint32(v.Status)),
					Memo:       &v.Memo,
					OperatedBy: &v.OperatedBy,
					OperatedAt: pointy.GetPointer(modelx.FormatNullDotTime(v.OperatedAt, "")),
				})
			}
		}
	}

	return resp, nil
}
